#region Using References

using System;
using System.Threading.Tasks;
using System.Windows.Input;
using Beaker.OpenCube.Dynamic;
using Beaker.OpenCube.Game;
using Beaker.Services.FileSystem;
using GalaSoft.MvvmLight.Command;

#endregion

namespace Beaker.OpenCube.WorldViewer.ViewModels
{
	/// <summary>
	/// ViewModel for the worlds that can be opened
	/// </summary>
	public sealed class OpenWorldViewModel
		: ViewModel
	{
		private readonly MainViewModel _owner;
		private readonly RelayCommand _openCommand;

		internal OpenWorldViewModel( MainViewModel owner, IFolder worldFolder )
		{
			_owner = owner;
			_worldFolder = worldFolder;
			_openCommand = new RelayCommand( Open );

			GetWorldInfoAsync();
		}

		private readonly IFolder _worldFolder;

		/// <summary>
		/// Gets the folder name of this world.
		/// </summary>
		/// <value>
		/// The folder name of this world.
		/// </value>
		public string WorldFolderName
		{
			get { return _worldFolder.Name; }
		}

		private string _worldName;

		/// <summary>
		/// Gets the name of this world.
		/// </summary>
		/// <value>
		/// The name of this world.
		/// </value>
		public string WorldName
		{
			get { return _worldName; }
			private set { SetValue( ref _worldName, value, OnWorldNameChanged ); }
		}

		private void OnWorldNameChanged( string oldName, string newName )
		{
			RaisePropertyChanged( () => DisplayName );
		}

		/// <summary>
		/// Gets the display name.
		/// </summary>
		/// <value>
		/// The display name.
		/// </value>
		public string DisplayName
		{
			get
			{
				if( !string.IsNullOrEmpty( _worldName ) )
					return _worldName;

				return _worldFolder.Name;
			}
		}

		private bool _isFlat;

		/// <summary>
		/// Gets a value indicating whether this world is flat.
		/// </summary>
		/// <value>
		///   <c>true</c> if this world is flat; otherwise, <c>false</c>.
		/// </value>
		public bool IsFlat
		{
			get { return _isFlat; }
			private set { SetValue( ref _isFlat, value ); }
		}

		private bool _isThundering;

		/// <summary>
		/// Gets or sets a value indicating whether it is thundering in this world.
		/// </summary>
		/// <value>
		/// <c>true</c> if it is thundering in this world; otherwise, <c>false</c>.
		/// </value>
		public bool IsThundering
		{
			get { return _isThundering; }
			set { SetValue( ref _isThundering, value ); }
		}

		private bool _isDay;

		/// <summary>
		/// Gets or sets a value indicating whether it is day in this world.
		/// </summary>
		/// <value>
		///   <c>true</c> if it is day in this world; otherwise, <c>false</c>.
		/// </value>
		public bool IsDay
		{
			get { return _isDay; }
			set { SetValue( ref _isDay, value ); }
		}

		private TimeSpan _dayTime;

		public TimeSpan DayTime
		{
			get { return _dayTime; }
			set { SetValue( ref _dayTime, value ); }
		}

		/// <summary>
		/// Gets the command to open this world.
		/// </summary>
		/// <value>
		/// The open command.
		/// </value>
		public ICommand OpenWorldCommand
		{
			get { return _openCommand; }
		}

		/// <summary>
		/// Opens this world.
		/// </summary>
		private void Open()
		{
			_owner.OpenWorld( _worldFolder );
		}

		private static readonly TimeSpan StartOfDay = TimeSpan.FromHours( 6 );
		private static readonly TimeSpan EndOfDay = TimeSpan.FromHours( 18 );

		private async void GetWorldInfoAsync()
		{
			LevelData levelData = await Task.Run( () =>
			{

				DynamicWorld world = _owner.Game.OpenWorld( _worldFolder );
				return world.LevelData;
			} );

			WorldName = levelData.LevelName;
			IsFlat = levelData.GeneratorName == "flat";
			IsThundering = levelData.IsThundering;
			IsDay = levelData.DayTime > StartOfDay && levelData.DayTime < EndOfDay;
			DayTime = levelData.DayTime;
		}
	}
}